package edu.scsu.csci.core;

import java.io.IOException;

import javax.servlet.ServletContext;

import edu.scsu.csci.config.ConfigurationException;
import edu.scsu.csci.config.XStreamConfig;
import edu.scsu.csci.converter.ConvertorRegistry;
import edu.scsu.csci.logging.ELogLevel;
import edu.scsu.csci.logging.ILogger;
import edu.scsu.csci.validator.TypeAnnotationRegistry;
import edu.scsu.csci.validator.ValidatorAnnotationRegistory;



/**
 *	Stores application level settings and constants.
 *
 * @author Maqbool Khan
 * @since jdk 1.5
 * @see
 */
public class ApplicationConfiguration {
	
	/**
	 * Application logger instance.
	 */
	private ILogger logger;
	
	/**
	 * Application context.
	 */
	private static ApplicationConfiguration applicationContext;
	
	/**
	 * Returns a the singleton instance of the application context.
	 * 
	 * @param servletContext
	 */
	public static ApplicationConfiguration getInstance(ServletContext servletContext){
		if(applicationContext == null){
			applicationContext = new ApplicationConfiguration(servletContext);
		}
		return applicationContext;
	}
	
	/**
	 * Cofigures the web application by reading the configuration file for all the 
	 * defined interceptors and convertors.
	 * 
	 * @throws ConfigurationException
	 * @throws IOException
	 */
	public synchronized void configure() throws ConfigurationException, IOException {
		this.logger.info("Setting up the convertor registry.");
		ConvertorRegistry.getInstance().setUp();
		
		this.logger.info("Setting up the type annotation registry.");
		TypeAnnotationRegistry.getInstance().setUp();
		
		this.logger.info("Setting up the validator registry.");
		ValidatorAnnotationRegistory.getInstance().setUp();
		
		this.logger.info("Creating an instnace of xStream wrapper to read the configuration file.");
		XStreamConfig xStreamConfig = new XStreamConfig();
		xStreamConfig.configure();		
	}
	
	/**
	 * Creates an instance of the application context.
	 * 
	 * @param servletContext
	 */
	private ApplicationConfiguration(ServletContext servletContext){
		String loggerClass = servletContext.getInitParameter("loggerClass");
		if(loggerClass == null){
			loggerClass = "edu.scsu.csci.logging.DefaultLogger";
		}
		System.out.println("Creating logger with the following implementaion class: " + loggerClass);
		this.logger = ILogger.LoggerFactory.create(loggerClass);
		
		String logLevel = servletContext.getInitParameter("logLevel");
		
		if(logLevel == null){
			logLevel = "debug";
		}
		System.out.println("Setting the log level to: " + logLevel);
		this.setLogLevel(logLevel);
	}
	
	/**
	 * sets the application wide log level.
	 * 
	 * @param logLevel
	 */
	private void setLogLevel(String logLevel){
		if("debug".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.DEGUG);
		}
		else if("info".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.INFO);
		}
		else if("warning".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.WARNING);
		}
		else if("error".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.ERROR);
		}
		else if("fatal".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.FATAL);
		}
		else if("off".equalsIgnoreCase(logLevel)){
			this.logger.setLogLevel(ELogLevel.OFF);
		}
		else {
			this.logger.fatal("No log level has been defined and hence the frame work would disable logging.");
			this.logger.setLogLevel(ELogLevel.OFF);
		}
	}
	
	/**
	 * Returns an instance of the application wide logger instance.
	 * 
	 * @return
	 */
	public ILogger getLogger(){
		return logger;
	}
	
}
